﻿using System;
using System.Security;
using System.Text;
namespace LeRenard.Core.Cryptography
{
    /// <summary>
	/// Defines a Base64 <see cref="Cryptographer"/>.
	/// </summary>
    public class Base64Cryptographer : ICryptographer<SecureString, string>
    {
        #region Construction
        /// <summary>
        /// Gets the underlying encoding used.
        /// </summary>
        public Encoding Encoding { get { return _encoding; } }
        private readonly Encoding _encoding;

        /// <summary>
        /// Initializes a new instance of the <see cref="Kdg.ExamenTool.Base64Cryptographer"/> class.
        /// </summary>
        /// <param name="encoding">The underlying <see cref="Encoding"/> used.</param>
        public Base64Cryptographer(Encoding encoding)
        {
            ThrowIf.Null(() => encoding);

            _encoding = encoding;
        }
        #endregion

        #region ICryptographer
        /// <summary>
        /// Encode the specified input.
        /// </summary>
        /// <param name="input">Input data to be encoded.</param>
        public string Encode(SecureString input)
        {
            try
            {
                var bytes = new byte[input.Length];
                bytes = _encoding.GetBytes(input.ToUnsecureString());
                var encoded = Convert.ToBase64String(bytes);

                return encoded;
            }
            catch (Exception ex)
            {
                throw new CryptographyException("Could not encode input to Base64. See innerException for details", ex);
            }
        }

        /// <summary>
        /// Decode the specified input.
        /// </summary>
        /// <param name="input">Input data to be decoded.</param>
        public SecureString Decode(string input)
        {
            try
            {                
                var decoder = _encoding.GetDecoder();

                var bytes = Convert.FromBase64String(input);
                var characaterCount = decoder.GetCharCount(bytes, 0, bytes.Length);
                var characters = new char[characaterCount];
                decoder.GetChars(bytes, 0, bytes.Length, characters, 0);
                var decoded = new SecureString();

                foreach (var character in characters)
                    decoded.AppendChar(character);

                return decoded;
            }
            catch (Exception ex)
            {
                throw new CryptographyException("Could not decode input from Base64. See innerException for details", ex);
            }
        }
        #endregion

        #region IDisposable
        public void Dispose()
        {            
        }
        #endregion
    }
}
